---@class ExpeditionMapItem
local MapItem = Class("")
function MapItem:ctor(obj)
    self.go = obj

    self.endTran = obj.transform:Find("EndPoint")
    self.startTran = obj.transform:Find("StartPoint")
    self.startPos = self.startTran.localPosition
    self.endPos = self.endTran.localPosition
end
function MapItem:GeEndWPos()
    return self.endTran.position
end
function MapItem:GeStartWPos()
    return self.startTran.position
end
ExpeditionMapMgr = {
    sceneRoot = nil,
    formationObjList = {},
    monsterObjList = {},
    currentStageId = nil,
    ---@type ExpeditionMapItem[]
    farList = nil,
    ---@type ExpeditionMapItem[]
    midList = nil,
    ---@type ExpeditionMapItem[]
    nearList = nil,
}
local this = ExpeditionMapMgr
function this.GetMapNamePath()
    return "Prefabs/MapPref/" .. this.GetMapName()
end
function this.GetMapName()
    local cfg = dataTable.getDataTableById("t_expeditionchapter", ExpeditionMgr.mapId)
    if cfg then
        local str = decodeJsonStrToTabel(cfg.f_MapRes)
        local id = ExpeditionMgr.GetCurStageId()
        local index = math.floor(id / 4) + (id % 4 == 0 and 0 or 1)
        log("map index "..index..",max:".. #str..",map:"..tostring(ExpeditionMgr.mapId))
        index = math.min(index, #str)
        index = math.max(index,1)
        return str[index]
    end
    return ""
end
--从0开始
function this.GetMapPosIndex(stageId)
    if not stageId then
        stageId = ExpeditionMgr.GetCurStageId()
    end
    local index = (stageId - 1) % 4
    return index
end
function this.LoadScene()

    if this.isLoading or this.sceneRoot then
        return
    end
    FireEvent(Config.EventType.ExpeditionStartLoading, true)
    if this.currentStageId == nil then
        this.currentStageId = ExpeditionMgr.GetCurStageId()
    end
    this.isLoading = true

    this.CheckLoad()
    this.loadCount = 1 + #this.loadPlayerTB + #this.LoadMonsterTB
    utimer.timeCall(this.StartLoad, 110, 1)

end
function this.CheckLoad()
    local formation = FormationManager.GetFormation(EnumConst.FormationType.Expedition)
    this.loadPlayerTB = {}
    this.LoadMonsterTB = {}
    for k, v in pairs(formation) do
        local id = tostring(v)
        if id ~= "0" and k < 6 then
            local hero = HeroManager.getHeroDatabyPartnerId(id,true)
            if hero then
                table.insert(this.loadPlayerTB, hero.partnerModelId)
            end

        end
    end
    --monster
    local info = ExpeditionMgr.GetCurrentStage()
    if not info then
        return
    end

    local flag = false
    if this.currentStageId == ExpeditionMgr.GetCurStageId() then
        this.needGotoNextArea = false
        if ExpeditionMgr.GetStageFullState(info.stageId) == ExpeditionMgr.StageState.open then
            flag = true
        end
    else
        this.currentStageId = ExpeditionMgr.GetCurStageId()
        this.needGotoNextArea = true
        flag = true
    end
    if flag then
        formation = info.formation
        for k, v in pairs(formation) do
            local id = v.modelId
            if id ~= 0 and k < 6 then
                table.insert(this.LoadMonsterTB, id)
            end
        end
    end
end
function this.StartLoad()
    local scene = this.GetMapNamePath()
    resMgr:LoadMapPrefab(scene, function(obj)
        ---@type GameObject
        local go = newObject(obj)
        this.sceneRoot = go
        local b = go.transform:Find("BattleMap")
        if b then
            b.gameObject:SetActive(false)
        end
        local root = go.transform:GetChild(0)
        this.farList = { MapItem.New(root:GetChild(0)) }
        this.midList = { MapItem.New(root:GetChild(1)) }
        this.nearList = { MapItem.New(root:GetChild(2)) }
        this.LoadDone()
    end)
    this.LoadFormation()
    this.LoadMonster()
end
function this.LoadMonster()
    for k, v in pairs(this.LoadMonsterTB) do
        local path = HeroManager.GetHeroDrawingRolePath(v)
        if path then
            this.LoadModel(k, path, this.monsterObjList, true)
        end
    end

end
function this.LoadFormation()
    for k, v in pairs(this.loadPlayerTB) do
        local useSkinId = logicMgr.SkinManager.getHeroSkinId(tonumber(v))
        local path = HeroManager.GetHeroDrawingRolePath(v,nil,useSkinId)
        if path then
            this.LoadModel(k, path, this.formationObjList, false)
        end
    end
end
--相机出屏，循环场景
function this.ExpandScene()
    this.DoExpandScene(this.nearList)
    this.DoExpandScene(this.farList)
    this.DoExpandScene(this.midList)

end
function this.DoExpandScene(mapItems)
    while true do
        local mapItem = mapItems[#mapItems]
        local endPos = mapItem.endPos
        local startPos = mapItem.startPos
        local screeWidth = Screen.width
        local mapItemTran = mapItem.go.transform
        local mapItemPos = mapItemTran.localPosition
        local point = this.camera:WorldToScreenPoint(mapItem:GeEndWPos())
        if point.x < screeWidth then
            local tran
            if #mapItems == 1 then
                local go = newObject(mapItem.go)
                tran = go.transform
                tran:SetParent(mapItemTran.parent, false)
                mapItemPos.x = mapItemPos.x + endPos.x - startPos.x
                Util.Lua_SetLocalPositionXYZ(tran, mapItemPos.x, mapItemPos.y, mapItemPos.z);
                table.insert(mapItems, MapItem.New(go))
            else
                local nextItem = mapItems[1]
                mapItemPos.x = mapItemPos.x + endPos.x - startPos.x
                Util.Lua_SetLocalPositionXYZ(nextItem.go.transform, mapItemPos.x, mapItemPos.y, mapItemPos.z);
                mapItems[1] = mapItem
                mapItems[2] = nextItem
            end
        else
            break
        end
    end
    this.DoExpandSceneLeft(mapItems)
end
function this.DoExpandSceneLeft(mapItems, isLeft)
    while true do
        local mapItem = mapItems[1]
        local endPos = mapItem.endPos
        local startPos = mapItem.startPos
        local mapItemTran = mapItem.go.transform
        local mapItemPos = mapItemTran.localPosition
        local point = this.camera:WorldToScreenPoint(mapItem:GeStartWPos())
        if point.x > 0 then
            local tran
            if #mapItems == 1 then
                local go = newObject(mapItem.go)
                tran = go.transform
                tran:SetParent(mapItemTran.parent, false)
                mapItemPos.x = mapItemPos.x - (endPos.x - startPos.x)
                Util.Lua_SetLocalPositionXYZ(tran, mapItemPos.x, mapItemPos.y, mapItemPos.z);
                table.insert(mapItems, 1, MapItem.New(go))
            else
                local nextItem = mapItems[2]
                mapItemPos.x = mapItemPos.x - (endPos.x - startPos.x)
                Util.Lua_SetLocalPositionXYZ(nextItem.go.transform, mapItemPos.x, mapItemPos.y, mapItemPos.z);
                mapItems[1] = nextItem
                mapItems[2] = mapItem
            end
        else
            break
        end
    end
end
function this.GetCameraPos(stageId)
    local cfg = dataTable.getDataTableById("t_longjourneysence", logicMgr.ExpeditionMgr.mapId)
    if not cfg then
        logError("找不到t_longjourneysence  " .. logicMgr.ExpeditionMgr.mapId)
        return Vector3.zero
    end
    local stageDistance = cfg.f_StageMove * this.GetMapPosIndex(stageId)
    local p = decodeJsonStrToTabel(cfg.f_StageCamera)
    local scale = p[2]
    local cameraPos = p[1]
    return Vector3.New(cameraPos[1] + stageDistance, cameraPos[2], cameraPos[3]), Vector3.New(scale[1], scale[2], scale[3])
end
function this.CreateCamera()
    local go = GameObject.New("camera")
    ---@type UnityEngine.Camera
    local camera = go:AddComponent(TCamera)
    camera.depth = -1
    camera.fieldOfView = 47

    local tran = camera.transform
    this.cameraTran = tran
    this.camera = camera
    tran:SetParent(this.sceneRoot.transform, false)
    local pos, scale = this.GetCameraPos(ExpeditionMgr.GetCurStageId())
    Util.Lua_SetLocalPositionXYZ(this.cameraTran, pos.x, pos.y, pos.z);
    Util.Lua_SetLocalRotationXYZ(this.cameraTran, scale.x, scale.y, scale.z)
end

function this.LoadDone()
    this.loadCount = this.loadCount - 1
    if this.loadCount <= 0 then
        this.isLoading = false
        local tran = this.sceneRoot.transform
        Util.Lua_SetLocalPositionXYZ(tran, -1500, -1500, 0);
        local cfg = dataTable.getDataTableById("t_longjourneysence", 1)
        for k, v in pairs(this.formationObjList) do
            v.transform:SetParent(tran, false)
            local heroId = this.loadPlayerTB[k]
           -- local hero = logicMgr.HeroManager.getHeroDatabyPartnerId(heroId)
            --if hero then
                this.InitSkin(v, heroId, true)
           -- end

            local json = cfg["f_HeroPosition" .. k]
            this.SetModelPos(v.transform, json)
        end
        for k, v in pairs(this.monsterObjList) do
            v.transform:SetParent(tran, false)
            this.InitSkin(v, this.LoadMonsterTB[k], false, 0)
            local json = cfg["f_MonsterPosition" .. k]
            this.SetModelPos(v.transform, json, true)
        end
        this.CreateCamera()
        this.ExpandScene()
        if this.needGotoNextArea then
            this.GotoNextArea(ExpeditionMgr.GetCurStageId())
        end
        FireEvent(Config.EventType.ExpeditionStartLoading, false)
    end
end
function this.InitSkin(obj, modelId, isSelf, level)
    --local hero = logicMgr.HeroManager.getHeroDatabyModelId(modelId,true)
    --if hero then
    local aniObj = obj.transform:Find("Animation").gameObject;
    --local skin = dataTable.getDataTableByStringId("t_roleconfig",hero.model,"skin")
    --if not string.IsNilOrEmpty(skin) then
    --    Util.SetSkin(aniObj,skin);
    --end
    logicMgr.EquipManager.setWeaponSkin(aniObj, modelId, isSelf, level);
    --end
end

function this.SetModelPos(tran, json, mirror)
    local cfg = dataTable.getDataTableById("t_longjourneysence", 1)
    local stageDistance = cfg.f_StageMove * this.GetMapPosIndex()
    local p = decodeJsonStrToTabel(json)
    local pos = p[1]
    local scale = p[2]
    Util.Lua_SetLocalPositionXYZ(tran, pos[1] + stageDistance, pos[2], pos[3]);
    local m = mirror and -1 or 1
    Util.Lua_SetLocalScaleXYZ(tran, scale[1] * m, scale[2], scale[3]);
end
function this.LoadModel(index, path, list)
    resMgr:LoadModelPrefab(path, function(obj)
        ---@type GameObject
        local go = newObject(obj)
        list[index] = go
        this.LoadDone()
    end)
end
function this.DestroyScene()
    destroy(this.sceneRoot)
    this.sceneRoot = nil
    this.cameraTran = nil
    this.camera = nil
    this.farList = nil
    this.nearList = nil
    this.midList = nil
    for key, value in pairs(this.formationObjList) do
        destroy(value)
    end
    table.clear(this.formationObjList)
    for key, value in pairs(this.monsterObjList) do
        destroy(value)
    end
    table.clear(this.monsterObjList)
end
function this.GotoNextArea(nextStage)
    local cfg = dataTable.getDataTableById("t_longjourneysence", 1)
    local stageDistance = cfg.f_StageMove * this.GetMapPosIndex(nextStage)

    local cameraPos = this.GetCameraPos(nextStage)
    Util.Lua_SetLocalPositionXYZ(this.cameraTran, cameraPos.x, cameraPos.y, cameraPos.z);
    this.isMoving = true
    local deltaDistance = 10
    for k, v in pairs(this.formationObjList) do
        local json = cfg["f_HeroPosition" .. k]
        local p = decodeJsonStrToTabel(json)
        local pos = p[1]
        local posX = pos[1] + stageDistance
        Util.Lua_SetLocalPositionXYZ(v.transform, posX - deltaDistance, pos[2], pos[3]);
        v.transform:DOLocalMoveX(posX, 2, false):SetEase(Ease.Linear):OnComplete(this.MoveDown)
        local anim = v.transform:Find("Animation").gameObject
        Util.PlayAction(anim, "move")
    end
    for k, v in pairs(this.monsterObjList) do
        local json = cfg["f_MonsterPosition" .. k]
        local p = decodeJsonStrToTabel(json)
        local pos = p[1]
        local posX = pos[1] + stageDistance
        Util.Lua_SetLocalPositionXYZ(v.transform, posX + deltaDistance, pos[2], pos[3]);
        v.transform:DOLocalMoveX(posX, 2, false):SetEase(Ease.Linear):OnComplete(this.MoveDown)
        local anim = v.transform:Find("Animation").gameObject
        Util.PlayAction(anim, "move")
    end
end

function this.MoveDown()
    if not this.isMoving then
        return
    end
    this.isMoving = false
    for k, v in pairs(this.formationObjList) do
        local anim = v.transform:Find("Animation").gameObject
        Util.PlayAction(anim, "fidle")
    end
    for k, v in pairs(this.monsterObjList) do
        local anim = v.transform:Find("Animation").gameObject
        Util.PlayAction(anim, "fidle")
    end
end